#pragma once

#include <iostream>
#include <functional>
#include <string>
#include <cassert>
#include <sys/epoll.h>
#include "Log.hpp"
#include "Error.hpp"
#include "sock_tcp.hpp"
#include "sock_tcp.hpp"
#include "Epoller.hpp"

class EpollServer
{
private:
    // typedef
    using func_t = std::function<std::string(std::string)>;
    // const
    static const int N = 4080;
    static const int defaultPort = 8888;
    static const int defaultFd = -1;

public:
    EpollServer(func_t func = nullptr, uint16_t port = defaultPort) : _port(port), _func(func)
    {
    }
    ~EpollServer()
    {
        _listenSock.Close();
    }

    void init()
    {
        logMessage(Debug, "EpollServer init");

        _listenSock.Socket();
        _listenSock.Bind(_port);
        _listenSock.Listen();

        _epoller.create();
        bool flag = _epoller.addEvent(_listenSock.Fd(), EPOLLIN);
        assert(flag);
        (void)flag;

        logMessage(Debug, "EpollServer init success");
    }

    void run()
    {
        logMessage(Debug, "PollServer run");

        // 1. 这里我们能够直接获取新的链接吗？
        // 2. 最开始的时候，我们的服务器是没有太多的sock的，甚至只有一个sock！listensock
        // 3. 在网络中， 新连接到来被当做 读事件就绪！
        // listensock_.Accept(); 不能！
        while (true)
        {
            // 1. 调用epool_wait
            int n = _epoller.wait(_events, N, -1);
            // 2. 判断结果
            if (n > 0)
            {
                // 2.1 有事件就绪
                // 2.2 分类处理
                logMessage(Debug, "poll success");
                handlerEvent(n);
            }
            else if (n == 0)
            {
                logMessage(Warning, "poll timeout");
                continue;
            }
            else
            {
                logMessage(Error, "poll error");
                continue;
            }
        }
    }

private:
    void handlerEvent(int n)
    {
        logMessage(Debug, "handlerEvent ...");
        // 2.1 遍历fd_array，找到就绪的fd
        for (int i = 0; i < n; ++i)
        {
            // a. 提取相关信息
            int fd = _events[i].data.fd;
            uint32_t events = _events[i].events;
            // b. 分类讨论
            if (fd == _listenSock.Fd())
            {
                // listensock就绪
                if (events & EPOLLIN)
                {
                    // 有新连接到来
                    accepter();
                }
                else
                {
                    // 其他情况
                    logMessage(Warning, "listensock error");
                }
            }
            else
            {
                // client sock就绪
                if (events & EPOLLIN)
                {
                    // 有数据到来
                    serverIO(fd);
                }
                else
                {
                    // 其他情况
                    logMessage(Warning, "client sock error");
                }
            }
        }
    }
    void accepter()
    {
        // 走到这里，说明listensock就绪了！调用accept是非阻塞的
        // 1. 调用accept
        std::string clientIP;
        uint16_t clientPort;
        int newsockfd = _listenSock.Accept(&clientIP, &clientPort);
        if (newsockfd < 0)
        {
            logMessage(Error, "accept error");
            return;
        }
        logMessage(Info, "client %s:%d connect success", clientIP.c_str(), clientPort);

        // 2. 将newsockfd添加到epoll中
        bool flag = _epoller.addEvent(newsockfd, EPOLLIN);

        if (!flag)
        {
            close(newsockfd);
            logMessage(Warning, "client %s:%d , epoll add error:%d", clientIP.c_str(), clientPort, newsockfd);
        }
        else
        {
            logMessage(Info, "client %s:%d , epoll add success:%d", clientIP.c_str(), clientPort, newsockfd);
        }
    }

    void serverIO(int fd)
    {
        std::string buf = _listenSock.Recv(fd); // TODO
        if (buf == "")
        {
            // 2.1 对端关闭
            _epoller.delEvent(fd);
            close(fd);
            logMessage(Info, "client shutdown: %d", fd);
        }
        else
        {
            // 2.2 正常接收
            // 3. send
            _listenSock.Send(fd, buf); // TODO
        }
    }

private:
    uint16_t _port;
    SockTCP _listenSock;
    func_t _func;
    struct epoll_event _events[N];
    Epoller _epoller;
};
